<!doctype html public "html2.0">
<html>
<head>
<title>IBM TSpaces Programmer's Guide</title>

</head>

<! Set white background with red and purple links ->
<body bgcolor="#ffffff" text="#000000" link="#CC0000" alink="#ff3300" vlink="#330099">
<!-- Masthead
<center>
<img src="gifs/masthead.gif" alt="TSpaces" ALIGN = "middle" BORDER = 0 width=600 height=54> 
</center>
-->
<center>
<H1>IBM TSpaces Programmer's Guide</H1>
</center>
<br clear=right>
<!----------------------------------------------------------------->
<h3><a name="intro">Introduction</h3>
<!----------------------------------------------------------------->
<p>
This initial version of the TSpaces programmer's guide will describe the 
client interface only.   
<p> 
It also contains a section on how to 
<a href="#server" >start the server</a>. 
If you are interested in more information on the TSpaces Server implementation,
you should read the
<a href="UserGuide.html#server" >Server overview</a> in the User Guide document. 
<p>
This guide applies to TSpaces 
<b>Version 2.1.2</b>

<p>
<hr>
<!----------------------------------------------------------------->
<h2><a name="basics">The Basic Definitions </h3>
<!----------------------------------------------------------------->
<p>
In this section we briefly discuss the basic objects that are used to 
implement a TSpaces client application. 
<p>

<UL>  

<p>
<!------------------------------------>
<LI><h4>Field</h4>
<!------------------------------------>
<p>
A 
<a href="./javadoc/com/ibm/tspaces/Field.html" target=new>
<b>Field</b></a>
object is the most basic component of the Tuplespace data
structure hierarchy.  A Field object contains:
<ul>
 <li> Type  (i.e. "java.lang.String" or "com.company.appl.EmployeeObject")
 <li> Value
 <li> Field Name (optional): Specifying a field name implies that this
     field will be indexed (and searched).
</ul>

<p>
<!------------------------------------>
<LI><h4>Tuple</h4> 
<!------------------------------------>
<p>
A <b>Tuple</b> object is an ordered sequence of Fields.
<p>
The 
<a href="./javadoc/com/ibm/tspaces/SuperTuple.html" target=new>
<b>SuperTuple</b></a>
class is where the interesting functionality of tuples is implemented,
but it's an abstract class, so clients should create either <b>Tuple</b>
or <b>SubclassableTuple</b> objects.
<p>
A <b>template</b> tuple is a Tuple  that is used for matching.  One or more of the Fields 
in a template may be "wildcards" and consist of only the class <b>type</b> with no value. 

<p>
<!------------------------------------>
<LI><h4>TupleSpace</h4>
<!------------------------------------>
<p>
A 
<a href="./javadoc/com/ibm/tspaces/TupleSpace.html" target=new>
<b>TupleSpace</b></a> 
is a shared named collection (bag) of Tuples. 
The basic operations supported by the collection are
to add a Tuple to the space (write), and to remove one from the space (take).

The collection is stored and administered across a network on one or more "T Space Servers". 
Several threads on the same or different machines can be accessing the space simultaneously. 
Some will be adding tuples to the space and some removing them.

A client thread accesses the collection/space using the methods of an instance of this class. 
For each different TupleSpace a client wishes to access, 
it requires a separate instance of this class, even if they are managed by
the same server. 
The details of how the operations are completed are hidden from the user. 
All they need is the name of the space, and the name of a server that manages that space.

<p>
A TSpaces server contains many Tuplespaces.
It is up to the application writer to decide whether to use one or many
tuplespaces for a particular application.  However, it is important to
know that it's really hard to run out of spaces, so there's no reason to
try to fit too many different tuple types into a single space.


<p>
The basic primitive operations supported by the space are:
  <ul>
  <li>write( tuple )    Adds a tuple to the space.
  <li>take( template_tuple )   Performs an associative search for a tuple that
                   matches the template.  When found, the tuple is removed
                   from the space and returned.  If none is found, returns null.
  <li>waitToTake( template_tuple )  Performs an associative search for a tuple
                    that matches the template.  Blocks until
                    match is found.  Removes and returns the
                    matched tuple from the space.
  <li>read( template_tuple )  Like "take" above, except that the tuple
                    is not removed from the tuple space.
  <li>waitToRead( template_tuple )  Like "waitToTake" above, except that the tuple
                    is not removed from the tuple space.
  <li>scan( template_tuple ) Like "read" above, except returns the entire set of 
                    tuples that match.
  <li>countN( template_tuple ) Like "scan" above, except that it returns a count of
                    matching tuples rather than the set of tuples itself.
  </ul>
<p>
The are also numerous other more specialized commands and there is an ability to
define your own specialized commands.

<p>
<hr>
<!------------------------------------>
<h2><a name="javaspaces">TSpaces, JavaSpaces and Linda</h2>
<!------------------------------------>
<p>
The concepts of TupleSpaces was first developed as part of the Linda System
at Yale University in the 1980s.  JavaSpaces&#153; from Sun MicroSystems is 
also based on Linda and an excellent book 
<a href="http://cseng.aw.com/bookdetail.qry?ISBN=0-201-30955-6&ptype=0" target=new >
JavaSpaces&#153; Principles, Patterns, and Practice</a>
has been written  
that covers the techniques of using "Spaces" for distributed programming.
The first chapter from the book is available 
<a href="http://developer.java.sun.com/developer/Books/JavaSpaces/introduction.html" target=new>online</a>

<p>
Although the examples in the book use the JavaSpaces implementation, it
is trivial to write the same examples using the TSpaces implementation 
of Tuplespace.  
The <a href=#helloworld><b>HelloWorld</b> example</a> described later is 
an example of how to convert a JavaSpaces application to TSpaces.


<p>
<hr>
<!------------------------------------>
<h2><a name="example1">Our 1st Example</h4>
<!------------------------------------>
<p>
Lets take a look at a some very simple code that will read and write data using 
TSpaces.  The following are just fragments of the code, for the complete 
source, look at the source for
<a href="../examples/simple/Example1.java" target=new>Example1.java</a> 
<p><pre>

  String  host  =  "tserver1.company.com";
        ...  
  TupleSpace ts = new TupleSpace("Example1",host);
  
   </pre>
The above will contact the TSpaces server that is running on the "tserver1" system 
and connect to the TupleSpace that is named "Example1".   
If the "Example1" TupleSpace does not 
exist, it will be created at this time. 
<p><pre>  
          
    Tuple t1 = new Tuple("Key1","Data1");  
    ts.write(t1);

    Tuple t2 = new Tuple("Key2",new Integer(999),"Data2");
    ts.write(t2);

    Tuple t3 = new Tuple("Key2","Data3");  
    ts.write(t3);   
   </pre>
The above will write 3 Tuples to the TupleSpace allocated previously.  Note that 
the 3 Tuples do not really need to all have the same type of Fields.  The 2nd Tuple 
has 3 Fields while the others have 2 Fields. 
<p> 
Also, the contents of the Tuple could have been directly coded in the write command.
or we could have done this the long way and directly allocated the Fields of the 
tuple.
The following are all equivalent:
<pre>
  Field f1 = new Field("Key1");
  Field f2 = new Field("Data1");
  Tuple t1 = new Tuple();
  t1.add(f1);
  t1.add(f2);
  ts.write(t1);
           -or-
  Tuple t1 = new Tuple("Key1","Data1");
  ts.write(t1);
           -or-
  ts.write("Key1","Data1");    
</pre>
<p>
Now we will read one of the above Tuples using the first field as a key and then 
extract the contents of the second field.
<pre>
  Tuple template = new Tuple("Key2", new Field(String.class));
  Tuple tuple = ts.read(template);
    
  String data = (String)tuple.getField(1).getValue();
</pre>  
The <b>read</b>
command will read the matching Tuple from the TupleSpace 
database and return it to the caller.  
The parameter passed to <b>read</b> is a template Tuple.  
A template Tuple is a Tuple that is used to select matching Tuples.  
It will contain 0 or more Fields that are either Actual Fields or Formal Fields.
<ul>
<li><b>Actual</b> Fields have a value that must be matched exactly 
against the corresponding Fields in the tuples that are in the TupleSpace.
<li><b>Formal</b> fields have a class but no value and only describe
the type of value that is to be returned. Basically they act as wildcards. 
</ul> 
In the example above,
the Field that results from <b>new Field(String.class)</b> is a Formal Field that would
match any Field that contains a <b>String</b> object.
<p>
The Tuple that is returned must exactly match the format of the 
template Tuple.  So in the example above, the Tuple("key2","Data3") will be returned.  
The Tuple("key2",new Integer(999),"data2") will not be returned because it does not 
match the format of the template. 
 
<p>
The <b>take</b>
command is similar to read but it will remove the matching Tuple from the TupleSpace 
database and return it to the caller. 



 
<p>
<hr>
<!------------------------------------>
<a name="import">Import Statements</h4>
<!------------------------------------>
<p>
The example above uses the simple TSpaces class names ( i.  e. Tuple).  The compiler needs to be able 
to translate this to the fully qualified name (i. e. com/ibm/tspaces/Tuple) 
so you need to add an import statement: 

<pre>
    import com.ibm.tspaces.*; 
</pre>
In the section on <a href="#compile">how to compile</a> we will describe how to point the compiler 
and runtime environment to the proper TSpaces library.
<p>
<hr>
<!------------------------------------>
<h2><a name="exceptions">Exceptions</h4>
<!------------------------------------>
<p>
The example above ignored exceptions that can be thrown by TSpaces.  
However, almost all of the TupleSpace methods can throw TupleSpaceException 
and therefore one needs to wrap the TSpaces code in Try/Catch blocks.
<br>For example:<br>
<pre>
   try {
     TupleSpace ts = new TupleSpace("Example1",host);  
     ts.write("Key1","Data1");
     ts.write("Key2",new Integer(999),"Data2");
     ts.write("Key2","Data3"); 
   } catch(TupleSpaceException tse) {
     System.out.println("TupleSpace Exception: " + tse.getMessage());  
     tse.printStackTrace();
   }
</pre>
Some of the examples that follow, may not show the try/catch in order to make the 
example easier to follow, but be assured, you <b>must</b> have either try/catch blocks or 
declare that the method throws TupleSpaceExecption. 
<p>
<hr>
<!------------------------------------>
<h2><a name="blocking">Blocking Commands</h4>
<!------------------------------------>
<p>
When an application issues a <b>WaitToRead</b> 
or <b>WaitToTake</b>
call, and the data is not yet there on the server, the application blocks on the
call until an answer is returned.  When a tuple arrives on the server
that matches the <b>Read</b> or <b>Take</b> query, it is sent to the
client and the application resumes.
<p>
As an example, assume that in a client running on machine1, you had the 
following code:
<pre>

    try {
        TupleSpace ts = new TupleSpace("Example",host);  
        SuperTuple answer = ts.waitToTake("3",new Field(String.class));
        ...
    } catch(TupleSpaceException tse) {
        System.out.println("TupleSpace Exception: " + tse.getMessage());        
    }
</pre>
<p>
And assume that in a client running on machine2, you had the 
following code:
<pre>

    try {
        TupleSpace ts = new TupleSpace("Example",host);  
        ts.write("1","Data1");
        Thread.sleep(5000);
        ts.write("2","Data2");
        Thread.sleep(5000);
        ts.write("3","Data3"); 
    } catch(TupleSpaceException tse) {
        System.out.println("TupleSpace Exception: " + tse.getMessage());        
    }
</pre>
Assuming that the applications started at the same time, the application on machine1 
would issue the <b>waitToTake</b> and then be blocked. However, about 10 seconds later
as soon as the matching Tuple arrived at the server, the server would send it to machine1 
which would unblock and process the matching Tuple.
<p> 
The default for blocking commands is to wait forever.  
However one can specify an optional timeout parameter to 
specify that if the operation has not be satisfied when the time 
limit is exceeded, then the waiting operation should be terminated and 
the <i>null</i> should be returned. 
So if we wanted to only wait for 60 seconds,
then the code above would now look like the following:
<pre>

    try {
        TupleSpace ts = new TupleSpace("Example",host);
        Tuple template = new Tuple( "3",new Field(String.class)); 
        SuperTuple answer = ts.waitToTake(template,60*1000));
        if (answer == null) {
          System.out.println("Operation timed out");
        ...  
    } catch(TupleSpaceException tse) {
        System.out.println("TupleSpace Exception: " + tse.getMessage());        
    }
</pre>

<p>
<hr>
<!------------------------------------>
<h2><a name="subclassabletuple">SubclassableTuple</h2>
<!------------------------------------>
<p>
The examples above used the Tuple class to contain the Fields that are written to or read
from a TupleSpace.  The Tuple class is a subclass of 
<a href="./javadoc/com/ibm/tspaces/SuperTuple.html" target=new>
<b>SuperTuple</b></a>
which is an abstract class and can not be instantiated.  
The Tuple class is declared <b>final</b> and cannot be subclassed.  
An alternative to Tuple is 
<a href="./javadoc/com/ibm/tspaces/SubclassableTuple.html" target=new>
<b>SubclassableTuple</b></a> which can be subclassed. 
<p>

Some of the advantages and disadvantages of defining your own SubclassableTuple are:
<ul>
<li><i>Advantage</i> You can use the constructors to make it easier to define 
tuple templates.  For example, you can have:
<pre>
     template = new SCTuple(key) 
instead of 
     template = new Tuple(key,new Field(String.class));
</pre>

<li><i>Advantage</i> You can simplify the code to retrieve data from the tuple.
For example, you can have:
<pre> 
    data = sctuple.getData()
instead of 
    data = (String)tuple.getField(1).getValue() 
</pre>
<li><i>Advantage</i> Your class that extends SubclassbleTuple can 
do validity checking of the Fields so that problems of applications 
that write "invalid" Tuples can be avoided.

<li><i>Disadvantage</i> The same version of the SubclassableTuple 
must be available on all of the clients and at the server.  
</ul>
<p>
It is important to note that since a SubclassableTuple is not a subclass of Tuple, 
one does not have to be concerned that a Tuple template will accidentally match a 
user defined SubclassableTuple.

<p>
<hr>
<!------------------------------------>
<h3><a name="example2">Our second Example</h3>
<!------------------------------------>
<p>
Let's take a look at an example that is similar to example1 but uses SubclassableTuple.
The following are just fragments of the code, for the complete 
source, look at the source for
<a href="../examples/simple/Example2.java" target=new>Example2.java</a> 


<p><pre>
    Example2Tuple mytuple;
    mytuple = new Example2Tuple("Key1","Data1");  
    ts.write(mytuple);
    
    mytuple = new Example2Tuple("Key2","Data3");
    ts.write(mytuple);   
   </pre>

<p>
The Example2Tuple is defined as shown below.
<pre>
  class Example2Tuple  
    extends SubclassableTuple 
       implements Serializable {
  
  public Example2Tuple(String key,String data) {
    super(key,data);
  }
  public Example2Tuple(String key)   {
    // build template if only one operand
    super(key,new Field(String.class));
  }

  public String
  getData()  throws TupleSpaceException {
  
    return (String)this.getField(1).getValue();
  }

</pre>
<p>
Now we will read one of the above Tuples using the first field as a key and then 
extract the contents of the second field.
<pre>
  Example2Tuple template = new Example2Tuple("Key2"));
  mytuple = (Example2Tuple)ts.take(template);
    
  String data = mytuple.getData();
</pre>
<p>
If you compare this to Example1, you will see that the interface to TupleSpace has been
simplified. In fact, a subclass of SubclassableTuple can be made into a JavaBean and make it 
very easy to use in a Java IDE.



<p>
<hr>
<!------------------------------------>
<h2><a name="helloworld">Hello World</h2>
<!------------------------------------>
<p>
No Programmer's Guide would be complete without a "Hello World" example.
In this example, we will give yet another example of TSpaces coding and also show 
how one would convert a JavaSpaces program to TSpaces.
The first chapter from the excellent book,
<i>JavaSpaces&#153; Principles, Patterns, and Practice</i> is available 
<a href="http://developer.java.sun.com/developer/Books/JavaSpaces/introduction.html" target=new>online</a>
This chapter contains a HelloWorld example and uses it to introduce JavaSpace 
programming.  We will use a somewhat different example and show both the
JavaSpaces and TSpaces example.  
For our example, we will show simple message passing between 2 programs.
One program will send a message to the "World" program and then wait for a 
reply.  The "World" program will wait for a message and when it gets it, 
it will send a reply back to the message's sender.
<p>
It is fairly easy to modify a JavaSpaces application to run under TSpaces.
Both systems have a common heritage but there are some terminology differences.  
Instead of defining Tuples, with
JavaSpaces, you define classes that implement the Entry class.  
These Entry objects then have Public instance variables that correspond to the 
TSpaces Field objects.  
One can fairly easily convert a JavaSpaces class that implements Entry 
into a TSpaces SubclassableTuple class.  
For this example, 
the <b>Message</b> class is the Entry object that we need to convert.
The JavaSpaces version is:
<pre> 
import net.jini.core.entry.Entry;
import java.io.Serializable;

public class Message implements Entry {
    
    public String to;
    public String from;
    public Serializable message;

    public Message() {
    }

    public Message(String to) {
        this.to = to;
        this.from = null;
        this.message = null;        
    }    

    public Message(String to, String from, Serializable message) {
        this.to = to;
        this.from = from;
        this.message = message;        
    }    
}
</pre>

The equivalent TSpaces Message class is:
<pre>
import com.ibm.tspaces.*;
import java.io.Serializable;

public class Message extends SubclassableTuple {
  
  public Message() throws TupleSpaceException {
    super(new Field(String.class),new Field(String.class),new Field(Serializable.class));
  }
  
  public Message(String to) throws TupleSpaceException {
    super(to,new Field(String.class), new Field(Serializable.class));
  }  
  
  public Message(String to,String from, Serializable message) throws TupleSpaceException {
    super(to, from, message);          
  }
  //
  // get/set methods for Destination, From and Message follow
  //
  public String getDestination() throws TupleSpaceException{    
    return (String)getField(0).getValue();  
  }
  
 
  public void setDestination(String to) throws TupleSpaceException{         
       getField(0).setValue(to);         
  }
  
  
  public String getFrom() throws TupleSpaceException{    
    return (String)getField(1).getValue();
  }
  
  
  public void setFrom(String to) throws TupleSpaceException{         
       getField(1).setValue(to);
  }
  
  
  public Serializable getMessage() throws TupleSpaceException{         
      return getField(2).getValue();
  }
  
  public void setMessage(Serializable message) throws TupleSpaceException{    
      getField(2).setValue(message);    
  }

}
</pre>
The major changes are:
  <ul>
  <li>JavaSpace implements the Entry Interface while 
TSpaces extends the SubclassableTuple class.
  <li>With JavaSpaces, you define the tuple data that is written to the 
  space with <b>public</b> instance variables whereas with TSpaces
  <b>accessor</b> methods are used to get and set the tuple Fields.
  </ul>
Although the TSpaces implementation is much longer, it is mostly 
boilerplate get/set methods. 
<p>
The class <b>Helloworld</b> then implements both halves of the message 
passing logic. It uses a parameter on the command line to identify itself
and then sees if it has a message waiting.  If so, it replies to it.
If not, it sends a message to "World" and then waits for a reply.
<p>The <b>HelloWorld</b> class for JavaSpaces is:
<pre>
import jsbook.util.SpaceAccessor;
import net.jini.core.lease.Lease;
import net.jini.space.JavaSpace;
public class HelloWorld {
    public static void main(String[] args) {
      String myName = "World";
      boolean needReply = false;    
      if ( args.length > 0) 
        myName = args[0];
      try {
        <b>JavaSpace space = SpaceAccessor.getSpace();</b>              
        Message template = new Message(myName);      
        <b>Message msg = (Message)space.takeIfExists(template,null,long.MAX_VALUE);</b>      
        if ( msg == null) {        
          msg = new Message("World", myName,"Hello World"); 
          needReply = true;
        } else {
          <b>msg = new Message(msg.from,myName,"Hi");</b>
        }            
        <b>space.write(msg, null, Lease.FOREVER);</b>      
        if (needReply) { // Wait for a reply      
          <b>msg = (Message)space.take(template,null,long.MAX_VALUE);</b>
        }
      } catch (Exception e) {
            e.printStackTrace();
      }
    } //main
} // class
</pre> 
<p>The <b>HelloWorld</b> class for TSpaces is:
<pre>
import com.ibm.tspaces.*;
public class HelloWorld {  
  public static void main(String[] args) {
    String myName = "World";
    boolean needReply = false;    
    if ( args.length > 0) 
      myName = args[0];    
    try {
      <b>TupleSpace space = new TupleSpace();</b>      
      Message template = new Message(myName);      
      <b>Message msg = (Message)space.take(template);</b>      
      if ( msg == null) {        
        msg = new Message("World", myName,"Hello World"); 
        needReply = true;
      } else {
        <b>msg = new Message(msg.getFrom(),myName,"Hi");</b>
      }            
      <b>space.write(msg);</b>      
      if (needReply) { // Wait for a reply      
        <b>msg = (Message)space.waitToTake(template);</b>        
      }      
    } catch (Exception e) {
        System.out.println(e);        
    }
  } //main
} //class
</pre> 

<p>
As you can see, other than import statements, 
there are only minor changes required.
  <ul>
  <li>The JavaSpace invocation of SpaceAccessor is replaced by 
  a call to the TupleSpace constructor. 
  <li>The JavaSpaces command write command is replaced with the 
  TSpaces write command with a slightly different signature. 
  <li>The JavaSpace read and take with a long wait interval are 
  replaced by TSpaces waitToRead and waitToTake commands. 
  <li>The JavaSpace takeIfExists command is replaced by the TSpaces
  take command.   
  </ul>
<p>
You can also just use the Tuple class to replace the need for the Message 
class. For many applications, this is simpler than defining a 
SubclassableTuple.  
We have included below the code for HelloWorld using only the Tuple 
class to define the Tuples that are written to the space.  
<p>

<pre>
package com.ibm.tspaces.examples.helloworld;

import com.ibm.tspaces.*;
import java.io.Serializable;

public class HelloWorldT {  
 
  public static void main(String[] args) {
    String myName = "World";
    boolean needReply = false;
    
    if ( args.length > 0) 
      myName = args[0];
    
    try {
      TupleSpace space = new TupleSpace();
      <b>
      Tuple template = new Tuple(myName,
              new Field(String.class),new Field(Serializable.class));</b>
      
      Tuple msg = space.take(template);
      System.out.println(msg);
      if ( msg == null) {
        <b>        
        msg = new Tuple("World", myName,"Hello World");</b> 
        needReply = true;
      } else {
        <b>
        msg = new Tuple((String)msg.getField(1).getValue(),myName,"Hi");</b>
      }            
      space.write(msg);      
      
      
      if (needReply) { // Wait for a reply      
        msg = space.waitToTake(template);
        System.out.println(msg);
      }
      
    } catch (Exception e) {
        System.out.println(e);      
    }
  }
}
</pre>

<p>
There are other differences between JavaSpaces and TSpaces not shown in the
example above. 
<ul>
<li>Both have Transaction support but they are implemented quite differently.
<li>TSpaces does not have Lease objects but you can specify an expiration
 interval for Tuples.
 <li>Both have methods for requesting to be notified when a Tuple matching a 
 template is written to the space but the implementation is different.
<li>TSpaces supports many additional commands such as scan(), count(), update()
  and others that are not implemented in JavaSpaces and although the 
  same end result can be achieved with JavaSpaces, it is more difficult and 
  often more inefficient.
 <li>TSpaces supports the ability to build indexes on the fields in a Tuple
  and issue query commands against the indexes. 
   
</ul>
<p>
<hr>
<!------------------------------------>
<h2><a name="scan">Scan - Returning Multiple Tuples</h2>
<!------------------------------------>
<p>
The <b>read</b> and <b>take</b> methods return a single matching tuple.  If more than one matches,
then it will return the first matching tuple.  However there are TupleSpace methods that will 
handle multiple matches.
<p>
<ul>
<li>

<b>countN(template)</b><br> 
This returns the integer count of the number of Tuples that match the specified template Tuple.

<li>

<b>scan(template)</b><br> 
This returns a Tuple that contains a set of Tuples that match the specified template Tuple.

<li>

<b>consumingScan(template)</b><br> 
This returns a Tuple that contains a set of Tuples that match the specified template Tuple and removes all of the 
Tuples from the server.
</ul>
<p>
Here is some sample code that makes use of countN and scan.
<PRE>
  
  Tuple  template = new Tuple("Key2",new Field(String.class));
  int count = ts.countN(template);
  if (count > 0) {
      Tuple tupleSet = ts.scan(template);
      if ( tupleSet != null) {
          for( Enumeration e = tupleSet.fields(); e.hasMoreElements(); ) {
              Field f = (Field)e.nextElement();
              Tuple tuple = (Tuple)f.getValue();
              data = (String)tuple.getField(1).getValue();
        ...
          }
      }
  }

</PRE>
<p>
First we create a template Tuple that will be used to select the Tuples from the server.
The next line issues <b>countN</b> to get the count of matches.
If we have 1 or more matches, then we issue the  
<b>scan</b> request to the tupleSpace using the template from earlier. This returns
a tuple "tupleset" that represents the set of matching tuples.

So "tupleset" contains one or more fields;
     the value of each field is one of the tuples
     returned by the scan.
So the next step is to use an Enumeration to extract each of the returned 
Tuples.
The <b>fields()</b> method returns an enumeration that can be
followed to access each individual Tuple. Once the individual Tuple is
accessed, the 
<b>getField(int).getValue()</b>
method is used to access the data in the Tuple.



<p>
<hr>
<!------------------------------------>
<h2><a name="events">EventRegister</h2>
<!------------------------------------>
<p>
One of the most useful features of TSpaces is the ability to register with the server to 
be informed when specific types of events occur.  For example, you might want to be informed 
whenever a Tuple that matches a specific template is written to the Server by any client.
With TSpaces this is done by using the TupleSpace.eventRegister() method to indicate the type of 
event you are interested in and specifying the Callback object that you want to have handle the event.
<p>

<!------------------------------------>
<h4><a name="example3">Our third Example</h4>
<!------------------------------------>
<p>
The following are just fragments of the code, for the complete 
source, look at 
<a href="../examples/simple/Example3.java" target=new>Example3.java</a> to see the code in context.  
Also, the 
<a href="examples.html#whiteboard" target=new>
whiteboard</a> sample program is an example of a real application that makes use of 
eventRegister to support multiuser communication. 
<p>
<pre>
  
  Tuple template = new Tuple( "Key2", new Field(String.class) );
  ExampleeCallback callback = new Example3Callback();
  boolean newThread = true;  // default is false
  int seqNum = ts.eventRegister(TupleSpace.WRITE, template, callback, newThread );
  ...
  ts.eventDeRegister(seqNum);    
</pre> 
<p>
The above sets up a template Tuple that describes the format of Tuples that we are interested in.
The eventRegister() method tells the server to watch for a Tuple being <b>written</b> to the TupleSpace  
that matches the <b>template Tuple</b>.  When this occurs, it should invoke the <b>call()</b> method for
the Example3Callback object.  The setting of <b>newThread</b> to true indicates that 
a new Thread should be started to process the callback.  
<p>
When you no longer want to be informed of Tuple events, you can remove the 
event registration with the eventDeRegister() method.  
<p>
<pre>

class Example3Callback implements Callback {

  public boolean 
  call(String eventName,String tsName,int seqNum,SuperTuple tuple,boolean isException)   {
    if (! isException) {          
      ... process the tuple passed to this method.
      String data = (String)tuple.getField(1).getValue();
    } else {
      ... handle exception 
    }
    return false;  
  } // call()
}    

</pre>
<p>
The above defines a class that implements the TupleSpace Callback interface. The Callback interface 
requires that it implements the <b>call</b> method with the following parameters:
<ul>
<li>eventName - String that indicates what type of TupleSpace action "Write" or "Delete"
  caused this call.  Note that only events that a cause a Write or Delete to be done are
  reported.  A READ operation at the server is not reported.
<li>tsName - Name of the TupleSpace.
<li>seqNum - Sequence number of the eventRegister call.
<li>tuple - The Tuple that matched the template.
<li>isException - A boolean that if true indicates that there was an exception processing 
the event.  In the case of an exceptional condition
occurring on the server, isException will be true and the exception will be inside the tuple,
( i.e., the tuple will contain one field that is a TupleSpaceServerException.)
</ul>
<p>
If the <b>newThread</b> variable in the above eventRegister call had been false,
then the method would have been invoked out of the server communication thread 
should do something really quick and
return, that is it should not take up lots of time. Typically, it might just verify that
isException is not true, and then queue  up the tuple and 
wake up some other thread that will do the real processing.
<p>
Normally this method would return <b>false</b>.
It would return <b>true</b> only if this is the last call this callback class is expecting.
<p>
<b>Warning:</b><br>
You cannot issue TupleSpace operations, (e. g. ts.write ) inside the call method 
unless the <b>newThread</b> option is set true. Otherwise
this will cause the client thread that handles communication with the 
server to hang.
<p>
<p>
<b>Warning:</b><br>
Although the Tuple that caused the event is passed to you in the callback, 
that does not mean that you have "control" of the Tuple.  It may have also 
been passed to other clients.  Depending on your purpose for getting the event,
you may want to do a "take" of the Tuple to ensure ownership of the Tuple.

<hr>
<!------------------------------------>
<h2><a name="other">Other TupleSpace Methods </h2>
<!------------------------------------>
There are a number of other TupleSpace methods that you should know about.  
Look at 
<a href="../examples/simple/Example6.java" target=new>Example6.java</a> to see the code in context.  
<h3>getVersion()</h3>
The <b>TupleSpace.getVersion()</b>
method returns a String that indicates the current level of the TSpaces client 
library. It is in the form "V.L.M".
Where "V" is the Version and is currently 1; "L" is the Level number; and
"M" is the Modification number.
<br>For example: 
     1.0.1 
<p>
The intent is that the "V" version number will change only 
for a very major change.
The "L" Level number will change when new major new 
features are added
and/or incompatible changes are made.
The "M" Modification number will change when a new level of 
compatible code is distributed to fix problems and possibly add minor  
new functions.

<!------------------------------------>
<h3>status()</h3>
<!------------------------------------>
The <b>TupleSpace.status()</b> method returns the status of the given server.  This is a useful 
way to verify that the server is active before you try to create a TupleSpace.
status() returns a simple Tuple that contains "Running" or "NotRunning" in
the first Field.  The 2nd Field contains the TSpace Server Version number.
<pre>
  Tuple active = TupleSpace.status(Host,Port);
  // 
  if ( active == null || active.getField(0).getValue().equals("NotRunning")) 
      System.out.println("Server not running on " +   Host+":"+Port );
  else 
     System.out.println("Server Version "+active.getField(1)+" is active on " +Host+":"+Port );
</pre>

<!------------------------------------>
<h3>exists()</h3>
<!------------------------------------>
The <b>TupleSpace.exists(Name,Host,Port)</b>
method returns true if the named TupleSpace exists on the Server at Host:port.
<!------------------------------------>
<h3>delete(Tuple template)</h3>
<!------------------------------------>  
<p>
The <b>delete(Tuple template)</b>
method will delete the Tuples that match the specified template Tuple.
<!------------------------------------>
<h3>deleteAll()</h3>
<!------------------------------------>  
<p>
The <b>deleteAll()</b>
method will delete all of the Tuples in the space.
This is equivalent to the following:
 <pre>
  Tuple all = new Tuple();
  ts.delete(all);  
 </pre>
The Tuple with no Fields acts as a wildcard that matches 
all Tuple objects.  
<P>
While we are on the subject of wildcards,  if you want 
to have a wildcard for one of the Fields that will match 
any object, then you would use the Serializable.class for the
Formal class.
<pre>
  ts.write("key","a string");
  ts.write("key",new Integer(99)); 
  
  Tuple template = new Tuple("key",new Field(Serializable.class));
  Tuple result = ts.scan(template);
</pre>
The above scan would pick up both Tuples because the Formal Field
matches any Field value that could have been written in a Tuple. 

<!------------------------------------>
<h3>multiWrite(Tuple TupleArray)</h3>
<!------------------------------------>  
<p>
The 
<b>multiWrite(Tuple tupleArray)</b>
method is an efficient way to write a large number of Tuples to the server. 
For example, during initialization, you may want to load the server with 
an initial set of data.  
<pre>
  Tuple multi = new Tuple();
  for (int i=0; i<10;i++) {            
    Tuple nextTuple = new Tuple("Test6",new Integer(i),"Tuple# "+i);
    multi.add(new Field(nextTuple));  // add Field to Tuple
  }
  TupleID[] ids = ts.multiWrite(multi);

</pre>
The above code creates the "multi" Tuple and then adds 10 Fields to it, where
each Field is a Tuple that is to be written to the TupleSpace. 
The multiWrite method returns a array of TupleIDs, one for each of
the individual Tuples. 

<!------------------------------------>
<h3>update</h3>
<!------------------------------------>  
<p>
The <b>update(uniqueId,updatedTuple)</b>
method will update a specific Tuple in the space.

<pre>
  Tuple newTuple = new Tuple("Data1");
  TupleID id = ts.write(newTuple);  
  Tuple updatedTuple = new Tuple("UpdatedData1");  
  id = ts.update(id,updatedTuple);
</pre>
The above code writes a Tuple to a space.  The write() method returns a <b>TupleID</b> 
that represents the uniqueId of this Tuple.  
This TupleID is then used to update the original 
Tuple.  The TupleID can also be obtained by calling the getTupleID() method
for a tuple that was read from the Space.  The TupleID for a Tuple is persistent and is
valid across restarts of the Server. 
<p>
There is also a <b>multiUpdate</b> command that is similar to MultiWrite. Given
an instance of TupleID, 
one can also use the <b>readTupleById(tupleid)</b> and the 
<b>deleteTupleById(tupleid)</b> commands to read or delete specific Tuples.

<!------------------------------------>
<h3>TupleSpace.cleanup()</h3>
<!------------------------------------>
The <b>cleanup()</b>
method is used to tell the server that you are finished 
with <b>all</b> of the TupleSpaces that you have created.  
<pre>
  TupleSpace.cleanup();

</pre>  
<p>
The <b>cleanup()</b>
method is a Class method that will close <b>all</b> of 
the active TupleSpaces.  It should only be used when you have finished with all 
TupleSpace activity.  The default tuplespace action is to use the Object <b>finalize</b>
method to take care of the cleanup.  Use of finalize may be cause an applet security 
violation so you can turn this behavior off by coding: 
<pre>
  TupleSpace.appletEnvironment(true);
  TupleSpace ts = new TupleSpace(...);    
</pre>

<p>
Another area where you need to use <b>cleanup()</b> is to have your client 
be able to recover and continue when a server goes down and then is restarted 
or when the network connection to the server is broken for a period of time.  
What you need to do on the client when the server crashes or goes down is to
recognise that it has gone down by intercepting the exception in the event
register callback or by catching the exception on the next Tuplespace
operation.    Then you need to make a call to cleanup() to cleanup the
existing connection and then reissue the "new TupleSpace(space,server)"

So it might look something like this.
<pre>
  TupleSpace ts = new TupleSpace(space,host);
  while (true) {
      try {
       while ( ts == null) {
            sleep(5000);
            ts = new TupleSpace(space,host);
       }
        Tuple result = ts.take(template);
      } catch(TupleSpaceException e) {
          System.out.println(e);
		  if (e.getMessage().indexOf("Server crashed")) {
            TupleSpace.cleanup(ts.getHost(),ts.getPort());
            ts = null;
		  }
      }
  }
</pre>
or in a callback.
<pre>
public boolean
call( String event,String space,int seq,
           SuperTuple tuple,boolean isException)  {

  if ( isException) {
     ts = null;
     return true;
  } else {
    ...
</pre>


<p>
<hr>  
<!------------------------------------>
<h2><a name=configtuple>Configuration Options</h2>
<!------------------------------------>
One can specify a number of options at the time a space is created using the 
ConfigTuple object.
<ul>
<li>FIFO -  <b>true</b> specifies that the results will be returned in FIFO order. 
The default is that results are returned unordered.  
<li>Persistence - <b>false</b> specifies that the TupleSpace will not be saved
across server restarts.  The default is that the space will be persistent (assuming
that the checkpoint directory was defined in the <b>tspaces.cfg</b> file).
</ul>
<pre>
    ConfigTuple config = new ConfigTuple();
    config.setOption(ConfigTuple.PERSISTENCE, Boolean.FALSE );    
    config.setOption(ConfigTuple.FIFO, Boolean.TRUE );     
    TupleSpace ts = new TupleSpace(MyTsName,host,TupleSpace.DEFAULTPORT, config);

</pre>



<p>
<hr>
<!------------------------------------>
<h2><a name=expire>Specifying Tuple expiration</h2>
<!------------------------------------>
Normally when a client writes a tuple to a space
it will stay in the space until some client does a <b>take</b> 
or <b>delete</b> for the Tuple.  However one can specify an expiration 
time value for the Tuple so that after the time expires, the Tuple will
be automatically deleted from the space.  
<p> 
<pre>
  Tuple myTuple = new Tuple("Hello","World);  
  myTuple.setExpire(5*60*1000);  // expire in 5 minutes
  ts.write(myTuple);
  SuperTuple result = ts.read(myTuple);  // will return myTuple
  Thread.sleep(5*60*1000);
  result = ts.read(myTuple);  // will return null
</pre>
<p>
Note that when the tuple expires, it is <b>not</b> 
reported to any eventRegister callbacks.

<p>
<hr>
<!------------------------------------>
<h2><a name="userobjects">User Objects</h2>
<!------------------------------------>
<p>
Our examples up to this point have all used Tuples with basic Java types like String and Integer.
However, subject to certain restrictions,
any Java object regardless if defined by the Java Language or by the user can be 
placed in a Tuple and written to and read from TSpaces.
<p>
The restrictions are:
<ul>
<li>The object must be Serializable.
<li>An equivalent class file for the object must be available to both the clients and the TSpaces server.
We will, however, describe how to avoid this restriction.
</ul>
<p>
<!------------------------------------>
<h3><a name="example4">Our fourth Example</h2>
<!------------------------------------>
<p>
The following are just fragments of the code, for the complete 
source, look at 
<a href="../examples/simple/Example4.java" target=new>Example4.java</a> 
to see the code in context.  

<p>
<pre>
  Example4Obj obj = new Example4Obj("User Object 1");
  Field f2 = new Field(obj);  
  ts.write("Key1",f2);
    
  obj = new Example4Obj("User Object 2");
  f2.setValue(obj);
  ts.write("Key2",f2);
  
  Tuple template = new Tuple("Key2",new Field(Example4Obj.class));
  Tuple mytuple = ts.take(template);
  Example4Obj objreturned = (Example4Obj)mytuple.getField(1).getValue();
</pre>    
The above looks much like the previous example except that previously, the 2nd Field was 
a String.  
<p>
Now we will look at the definition of the class:
<pre>
class Example4Obj    implements Serializable, Comparable {
  
  static final long serialVersionUID = -2475757193974756987L;
  
  String userdata;

  public String
  getData()   {  
  return userdata;
  }

  public boolean 
  equals( Object other ) {      
    if ( (other == null) || ! (other instanceof Example4Obj) ) 
      return false;    
    if ( userdata == null ) 
      return ( ((Example4Obj)other).getData() == null);     
    return userdata.equals(((Example4Obj)other).getData());
  }  // end equals()

 
 public int 
  compareTo( Object other ) {      
    if ( (other == null) || ! (other instanceof Example4Obj) ) 
      return +1;    
    if ( userdata == null ) 
      return ( -1);     
    return userdata.compareTo(((Example4Obj)other).getData());
   
    
  }  // end compareTo()
}
      
</pre>

<p>
The things to note in this definition are:
<ul>
<li>The class is declared to implement Serializable.  
<p>
<li>An equals() method has been added.  This is required if you 
you plan to use the object as a search field in a template.  The 
equals() method will override the Object.equals(Object other) method.
This method will be invoked on the server to match a supplied 
template (represented by "this") to the instances of Example4Obj that
are in the database.
You should be careful to handle all the possible cases such as null values.
<p>
<li>This shows an example of having specified serialVersionUID. 
This string is generated by running the <b>serialver</b> program that 
is distributed with the Java JDK and  the class.  The resulting 
output is then cut/pasted into the .java file.  
The advantage of doing this is that you can make minor changes to the 
class at the client without having to copy the class file to the ClassPath 
used by the TSpaces server.  The disadvantage is that if you make
changes to the client version that are NOT compatible with the server version,
you may lose data or get an exception when you try to write or read the object
from the TSpaces server.  
<p>
<li>The class is declared to implement Comparable and a <b>compareTO</b>
method has been added.  
This requires use of Java2 (Java 1.2) which defines the Comparable interface.
By implementing Comparable, this object could be used in a named field and the 
index support in TSpaces can be used to search for a match or a range. 
If you are using Java 1.1, then you cannot make use of this feature unless
you copy the Comparable.class file from a Java 1.2 system to a directory 
in your classpath
</ul>
<p>
<!------------------------------------>
<h3><a name="example4a">Our fourth Example using FieldPS</h2>
<!------------------------------------>  
<p>
In many cases,  it is not feasible to ensure that the class definition 
for a client defined object be available in the TSpaces server.  
The best way to bypass this problem is to serialize the object into a byte array
prior to sending it to the server and just send the server a field that is defined as 
<b>byte[]</b>.  
The <A HREF="javadoc/com/ibm/tspaces/FieldPS.html" target=new>FieldPS</a> object 
is designed to do this Field Pre Serialization.  <b>FieldPS</b> is a subclass of <b>Field</b> 
and acts like a Field object except when handed an Object, it automatically serializes it into
a <b>byte[]</b> object and stores that.  When requested to return the value of the Field,
it automatically returns the deserialized value.  

<p>
Here is an example of the use of <b>FieldPS</b>.
The following are just fragments of the code, for the complete 
source, look at 
<a href="../examples/simple/Example4a.java" target=new>Example4a.java</a> 
to see the code in context.  

<p>
<pre>
  Example4aObj obj = new Example4aObj("User Object 1");
  
  FieldPS f2 = new FieldPS(obj);  // <---changed  
  ts.write("Key1",f2);
    
  obj = new Example4aObj("User Object 2");
  f2.setValue(obj);  
  ts.write("Key2",f2);

    
  Tuple template = new Tuple("Key2",new FieldPS(Example4Obj.class));
    Tuple mytuple = ts.take(template);
    Example4Obj objreturned = (Example4Obj)mytuple.getField(1).getValue();
  
</pre>
Note that only the statement that defines the 2nd Field has changed.  All of the
rest of the code is identical.  It is important to also note that you use
<b>FieldPS</b> when you define the template to retrieve the tuple.  Also, any 
attempt to do matching on the FilePS field will probably fail since 2 equal objects
may very likely have different serialized representations. 
But you can have one of the other
Tuple Fields be the value that you want to match on.  
For example, if you wanted to match on the "userdata" field in the Example4Obj object,
you could add another
Field to the Tuple that would contain the value of userdata;
<pre>
  ts.write("Key1", obj.getData(), new FieldPS(obj));
</pre>






<p>
<hr>
<!------------------------------------>
<h2><a name="Transactions">The Transaction Model </h2>
<!------------------------------------>
<p>

In what has been discussed so far, client application programs create
their own version of a space and invoke various operations like read,
write, blocking read, blocking write etc. In general, a client program
consists of a set of operations performed on one or more spaces. It is not
hard to think of applications where all operations must appear as one
atomic unit to anyone interested in the actions performed by the
application. This suggests a transaction model. 
<p>
Each operation unless specified to be part of a transaction is considered
to be a stand-alone transaction. To execute operations as a transaction,
the client application creates an instance of a 
<a href="./javadoc/com/ibm/tspaces/Transaction.html" target=new><b>Transaction</b></a>
class and calls the <b>beginTrans()</b> method of the Transaction class on it. 
A TupleSpace
object can be added to the Transaction object using the addSpace() method
of the Transaction class. Any operation performed on a TupleSpace instance
that has been added to a Transaction object, belongs to the transaction
corresponding to that Transaction object, if performed after the start of
the transaction.  
The <b>commitTrans()</b> method of the Transaction class is
called to make the effect of operations in the transaction visible to
other transactions. 
The <b>abortTrans()</b> method can be called to undo all of the operations that 
belong to the current transaction.
<p>
The following is an example of how a client program
can make use of the transaction model. In the example, 
either all 3 of the writes will succeed or none of them
will succeed.
You can also look at 
<a href="../examples/simple/Example7.java" target=new>Example7.java</a> to see a 
more complete example of how the Transaction support is used.  

<pre>
    Transaction trans = new Transaction();
    
    TupleSpace ts = new TupleSpace("testing");

    trans.addSpace(ts);    
    
    trans.beginTrans();
    // start of transaction
    
    ts.write("email", "to", "dick@sun");
    ts.write("email", "text", "Hello");
    ts.write("email", "from", "jane@ibm");
    
    
    trans.commitTrans();
    // end of transaction
</pre>
<p>
<hr>
<!------------------------------------>
<h2><a name="ClientAccessControl">Access Control for the Client </h2>
<!------------------------------------>
<p>
A client application can identify the userid that it is associated with. 
This is done either by:
<ul>
<li>Using the TupleSpace.setUserName(String) and setPassword(String) methods.
<li>Using additional userid and password parameters on the 
TupleSpace constructor that allocates a Space.  
</ul>
If specified, then the SHA-1 Secure
Hash Algorithm is used to create a hashed password and the userid and hashed password
are sent to the host where they will be verified by the server.  If the user 
and password are not specified, then the userid is assigned as "anonymous".  For many 
applications, running as anonymous will be completely satisfactory. 
<p>
Access control is on a TupleSpace operation level; each operation defined on a
TupleSpace has an associated list of <i>AccessAttributes</i> that must
be satisfied by any client trying to execute that operation. For
example, the <b>take</b> operation requires either the general <i>Read</i> and <i>Write</i> 
<b>AccessAttributes</b> or the more specific <i>Take</i> <b>AccessAttribute</b>.  
<p>

The access levels for a TupleSpace are granted to a Principal based on 
an Access Control List (ACL) for that space. A Principal is any
defined User or Group.  The Acl contains entries that define a
Principal and the permissions that the Principal is granted.
<p>  
Like most systems, groups are just groupings of users and users can be members of 
different groups.  Permissions that are granted to a group are passed to all the groups 
and users that are members.  

 
<p>
The access rights for a TupleSpace are granted when the TupleSpace is 
created.  If not specified in the TupleSpace constructor, then a default Acl is 
assigned to the space when it is initially created.    
  
<p>
Additional information on setting up access control at the server can be found in
<a href="#ServerAccessControl">Setting up Access Control for the Server</a> section of this document


<p>
<!------------------------------------>
<h2><a name="example5">Our AccessControl Example</h2>
<!------------------------------------>
<p>
Let's take a look at an example that is similar to Example1 but makes use 
of AccessControl.
The following are just fragments of the code, for the complete 
source, look at the source for
<a href="../examples/simple/Example5.java" target=new>Example5.java</a> 


<p>
First we create a Tuple that describes the access permissions that we want to 
grant to this TupleSpace.
<pre>
String owner = MyUserid;  // some code to fill in the current userid      
AclEntry ae1 = AclFactory.createAclEntry("Users",P_READ);
AclEntry ae2 = AclFactory.createAclEntry("anonymous",P_READ);
ae2.setNegativePermissions();
AclEntry ae3 = AclFactory.createAclEntry(owner,new Permission[] {P_READ,P_WRITE});
      
Acl myacl = AclFactory.createAcl("ExampleTS",ownere,
          new AclEntry[] {ae1,ae2,ae3});
Tuple permission = new Tuple((Serializable)myacl);

 </pre>

The above code creates an Access Control List (Acl) that will give:
<ul>
<li> "Read" access to everyone in the "Users" group.
<li> "Remove "Read" access for the "anonymous" user, who is in the Users group.
<li> "Read" and "Write" access to my userid.
</ul>
<p>
<pre>  

  TupleSpace ts = new TupleSpace("ExampleTS,
      host,TupleSpace.DEFAULTPORT,null,
      permission,  
      MyUserid,MyPassword);
</pre>
The above TupleSpace constructor now has more parameters than what we have seen in earlier 
examples.  The 5th parameter("permission") is the Tuple that we built above.  
The 6th and 7th paramters are the userid and password for the user that is running this
application.  This information would have been obtained by prompting the user 
for it.
<p>
As a result of the above, your userid will be able to read and write to the 
TupleSpace and all other users except "anonymous" will be able to read from the 
space.  The user "anonymous", which is the default userid when no user is specified, 
will not have any access to the space.

<p>
An alternative method for specifying the userid and password information is the following:
<p>
<pre>
  TupleSpace.setUserName(Myuserid);  
  TupleSpace.setPassword(MyPassword);
  boolean exists = TupleSpace.exists("ExampleTS",host);
  if (exists) {
    ts = new TupleSpace("ExampleTS",host);
  } else {
    ts = new TupleSpace("ExampleTS",host,TupleSpace.DEFAULTPORT,null,permission);  
  }
</pre>
This method is preferred when the <b>exists()</b> method is used because 
the authorization must be set prior to invoking the exists method.  
111
<hr>
<!------------------------------------>
<h2><a name="query">Querying the Database</h2>
<!------------------------------------>

There are 4 types of Queries: MatchQuery, IndexQuery, AndQuery, and OrQuery.
<p>
There is also an XMLQuery, but this is described in the 
<a href="#xml">XML section</a>.
In the set of sample programs that are provided with tspaces, there is the 
<a href="./examples.html#superheros" target=new>
SuperHeros</a> sample that is a good example of using the query facilities of 
TSpaces.
<h4>Default Behavior</h4>

If a Tuple is used in a query-type method (read, take, scan, or count)
that contains Queries in its fields, these Queries will be combined
into a single AndQuery by default.  If the fields of the tuple are not
Queries, the tuple will be converted into a MatchQuery.

<h4> MatchQuery</h4>

Match queries take a SuperTuple, and return everything that matches.
For example:
<pre>
Tuple tup = new Tuple( "tuple1", "3" );
Tuple result = ts.scan( new MatchQuery( tup ) );
</pre>
This code will return all tuples that exactly match the given tuple. 
The result is the same as if template match was used. (i.e. the following
would be equivalent to the above.)
<pre>
Tuple result = ts.scan("tuple1","3");
</pre>
<p>

<h4>IndexQuery</h4>

An IndexQuery takes an index name and an Object representing a value to be found in the index:
<pre>
Tuple result = ts.scan(new IndexQuery( "foo", new Integer(8) ));
</pre>
This code will return all tuples with the Integer value 8 in the field named "foo".
<p>

Alternatively, the Object passed to the IndexQuery can be a Range.
The Range constructor takes two parameters (upper and lower bound).
If neither upper nor lower bound is null, it's a normal exclusive
range (i.e. everything strictly greater than the lower bound and
strictly less than the upper bound).  If either bound is null, it's an
open-ended range (e.g.  lower bound null will return everything less
than the upper bound):
<pre>
Range myRange = new Range(null, new Integer(8));
Tuple result = ts.scan(new IndexQuery( "foo", myRange ));
</pre>
This example will return all tuples with a value less than 8 in the
field named "foo".
<p>
The IndexQuery requires the use of <b>named</b> Field objects.
For Example:
<br> 
<b> Field f = new Field("keyfld",new Integer(345765))</b>
<br>will define a Field with the name of "keyfld". All Tuples that
contain a "keyfld" Field will be indexed.
<p>
<h4>AndQuery and OrQuery</h4>

The constructors for AndQuery and OrQuery take two Queries.  These
queries will both be applied, and the results combined.  These can be
used to nest queries to arbitrary depths:

<pre>
ts.scan(new AndQuery(new OrQuery(new IndexQuery("index1", new Range(new Integer(3), new Integer(7))),  
                                 new IndexQuery("index2", new Range(new Integer(6), new Integer(9)))),
                     new MatchQuery(new Tuple(new Field(Integer.class), new Field(String.class) )))
</pre>
This query will return all tuples with structure matching
(Integer,string) and having either a value (strictly) between 3
and 7 in the "index1" field, or a value strictly between 6 and 9 in
the "index2" field.  Note that order may be important here.  Currently the Query
is not optimized such that the "smallest" query is always applied first.
<p>
<b>Restrictions:</b>
<ul>
<p>
<li>These query facilities only apply to the MMDB TupleSpaces. 
If you specify "SMALLDB" in the configuration, you can only use the simple matching 
described in the previous sections. 
<p>
<li>You can index any of the following Objects: String, Integer, 
Long, Short, Byte, Character, Double and Float.   If you are running 
Java2 (Java 1.2), then you can index any object that implements the 
<b>Comparable</b> interface.  

</ul>

<hr>
<!------------------------------------>
<h2><a name="applet">Using TSpaces in an Applet</h2>
<!------------------------------------>
There are a number of special considerations that should
be kept in mind when you are using TSpaces inside of an Applet.
<p>
Let's take a look at an example Applet.
The following are just fragments of the code, for the complete 
source, look at the source for
<a href="../examples/simple/AppletTst1.java" target=new>
AppletTst1.java</a> 

<ul>

<li><b>appletEnvironment()</b><br></li>
There are some operations that TSpaces uses that would cause TSpaces to 
violate the applet security constraints.  However, you can tell TSpaces to 
avoid these by adding the following statement somewhere early in your 
init() method.
<pre>
  TupleSpace.appletEnvironment(true);
</pre>

<p>
<li><b>Determining Server location</b><br></li>
Because of Applet security restraints, the TSpaces server must reside 
on the same system as the applet. As described in a later section, 
one can use the 
<a href="#httpserver">HTTP Server</a>
included in TSpaces to distribute the applet 
or one can run any standard HTTP server on the TSpaces host system.
In the downloaded applet, one can then determine the host address 
for Tspaces by using the applet getCodeBase() method.
<pre>
    URL url = getCodeBase();
    String urlhost = url.getHost();    
    TupleSpace ts = new TupleSpace("myspace",urlhost)
    
</pre>

<p>
<li><b>destroy() method considerations</b><br>
Because the Netscape and InternetExplorer browsers contain
a single Java Virtual Machine that runs all applets, 
class resources that are 
allocated by an applet remain allocated for the life of the 
browser rather than the life of the applet.  For this reason, 
there is an applet <b>destroy()</b> method that can be used to 
deallocate applet resources.  
It is important that the destroy() method be used to free TSpaces 
resources by calling the TupleSpace.cleanup() method.
Also any <b>eventRegister</b> callbacks should be canceled with
the eventDeRegister() method.  
<pre>
  public void 
  init() {
    if (instanceCount > 0 ) {
      // fail applet with message
    } else {
      instanceCount++;      // keep track of how many are started
    }
    ...

  public void 
  destroy()  {    
    instanceCount--;    
    if (instanceCount == 0) {
      try {
        _ts.eventDeRegister(_seqNum);      
      } catch (TupleSpaceException tse) {
        Debug.out(tse);
      }
      TupleSpace.cleanup(_ts.getServer(),_ts.getPort());
      _ts = null;     
    } 
  }
</pre>
<p>
Note that there is an instance count that is used in this case to 
prevent 2 instances of the applet from running.  
This is one simple way to prevent one instance of an applet 
from destroying the environment for another instance 
of the applet.   
<p>
<li><b>Other considerations</b><br>
There appears to be a requirement with Internet Explorer 4 or 5 
to have the applet and any classes required by the applet to either
all be class files named by the CODEBASE parameter or 
all be in the jar file named by the ARCHIVE parameter in HTML.
Strange!
<p>
<li><b></b><br>

</ul>

<hr>
<!------------------------------------>
<h2><a name="handlers">Implementing New Command Handlers</h2>
<!------------------------------------>
<h4>Overview of TSpaces Factory objects and Handler objects.</h4>
<ul>
A TupleSpace (or "TS" on the server) is the combination of a
<b>database</b> (TSDB) object and a stack of <b>Tuple Space Handler Factory 
(TSFactory)</b> objects.  
A database is the data structure responsible for storing and 
indexing a collection of Tuples on the server.  A <b>TSFactory</b>
is a class that is responsible for producing an instance
of a <b>Tuple Handler (TSHandler)</b> for each "command" Tuple that is
sent to the space.  It is the <b>TSHandler</b> that implements the command
specified in the Tuple.
<p>
The indirection that results from this scheme makes it possible to
easily alter the handlers associated with a space. By adding a new 
factory it is possible to completely alter the semantics of a 
space. The selection of a handler is completely up to the factory, 
and the implementation of a command is completely up to the handler.
<p>   
By stacking factories so that a new one passes any commands it doesn't
recognize along to the previous factory, it is possible to augment 
the semantics of a space (adding a new command for instance) without 
the need to completely implement basic functionality.
<p>
TSpaces allows a user with <i>ADMIN</i> authority for the server to add TSFactory 
and TSHandler objects dynamically at runtime.  This makes TSpaces 
extremely flexible
</ul>

<h4>AddHandler example</h4>
<ul>

To show how one would implement new commands and modify the semantics of existing 
commands, we have included an example
<a href="./examples.html#handler" target=new>"handler"</a>  
that will handle automatic deletion of Tuples 
after a specified time.  This will involve modifying the <b>Write</b> command so that
it will add a timestamp to the tuple before it is written to the database and 
implementing a new command <b>START</b> that will startup a new thread in the 
server that will periodically delete the expired Tuples.
<p>
Note: We have since added Tuple Expiration to the base system so 
this is a useless example but it is still a good example.
<p>
To implement the behavior that we want, we have defined <b>StaleTuple</b>, 
which is a SubClassableTuple, and <b>StaleTupleSpaceHandler</b>.  
<p>
<a href="../examples/handler/StaleTuple.java" target=new><b>StaleTuple</b></a> 
is used to hide the details of the Tuple format under get and set methods
and is similar to our earlier example of a
<a href="#subclassabletuple">SubclassableTuple</a>  
<p>
<a href="../examples/handler/StaleTupleSpaceHandler.java" target=new>
<b>StaleTupleSpacehandler</b></a> is where all of the interesting code resides.
Since the implementation of a handler at runtime involves both 
client and server actions, let's look at the client actions first.
The client code that will be invoked is in the <b>main()</b> method for 
StaleTupleSpacehandler.  In a real application, this would more likely be 
part the application code but it is convenient here to bundle it all in one file.
<p><pre>

       TupleSpace ts = new TupleSpace(TSName,
               Host,TupleSpace.DEFAULTPORT,
              null,null,  
              MyUserid,MyPassword);  
</pre>
This will create a TupleSpace with the specified name on the specified 
server.  Note that we specify our userid and password which in our case was
specified on the command line but could have been prompted for with a GUI 
interface.  This userid <b>must</b> have <b>ADMIN</b> authority for the Server
so that we will have the authority to issue the following methods.

<p>
Now we will add a TSFactory object that supports downloadable handlers.  We have 
supplied <b>TSFExtendable</b> which will satisfy this need. 
<pre>
 final String FN = "com.ibm.tspaces.server.handler.TSFExtendable";
    
 ts.addFactory( new Class[] { Class.forName(FN)} );      
</pre>

<p>
Now we will create an instance of StaleTupleSpaceHandler and issue an
addHandler 
command for each new or modified command that this handler will service.
<pre> 
      StaleTupleSpaceHandler dh = new StaleTupleSpaceHandler();
      
      ts.addHandler( TupleSpace.WRITE, new Class[] { dh.getClass()} );
      ts.addHandler( StaleTupleSpaceHandler.START, new Class[] { dh.getClass()} );
</pre>
<p> 
We will now issue the START command and use our modified Write command to write an 
instance of StaleTuple to this TupleSpace.  
<pre>
   Tuple argtuple = new Tuple(60*1000);  
      
   ts.command( StaleTupleSpaceHandler.START,argtuple);

 
   StaleTuple test1 = new StaleTuple("key1","some data");
   test1.setTimeToLive(15000);   // 15 seconds of life

   ts.write(test1); 
</pre>                                          
The above code issues the new START command and specifies that
the new thread should be invoked every 60 seconds.  Note that we 
have to use the 
TupleSpace.command() 
method since the TupleSpace class doesn't know anything about "START".
The <b>command()</b> method will simply send the START command and any argument Tuple 
to the server.  
However, the normal TupleSpace.write command can be used 
but at the server our new 
implementation will be invoked for this particular space. 
As we will see in the next section, our new write implementation will 
use the specified TimeToLive value to generate a timestamp that is 
added to the StaleTuple before it is written to the database.  
<p>
Now let's look at the implementation of the StaleTupleSpaceHandler.  
There are a number of methods that are required to be present for 
a Command handler to implement or extend commands.  
In addition to the brief description here,
the sample code has comments that describe what is needed.
<ul>
<li>Null Constructor<br>
The null constructor is called by the Factory to construct the handler.

<li>handles()<br>
The <b>handles()</b>method is called by the Factory to determine if the 
command handler wants to handle this command and the SuperTuple that is passed
to it.  It would normally return <b>true</b>.
<li>attributes()<br>
The attributes() method returns the Permission that a client must have to 
invoke the command.  As shown below, the method returns an array of permissions that
the user must have.
<pre>
  public AccessAttribute [] 
    attributes(String cmdString, SuperTuple argTuple) 
    throws TSHandlerException {
  
      AccessAttribute admin[] = { AccessAttribute._ADMIN_ATTRIBUTE };
      AccessAttribute write[] = { AccessAttribute._WRITE_ATTRIBUTE};

      if(cmdString.equals(TupleSpace.WRITE)  ) 
        return write;
      if(cmdString.equals(StaleTupleSpaceHandler.START)  )
        return admin;
      
  } // attributes
</pre>  
<p>
<li>command()<br>
The <b>command</b> method is the real meat of the implementation.  
We show below a simplified implementation of the "WRITE" command.
It first calls a method in StaleTuple that places the current date/time
stamp into the 1st field of the tuple.  It then extracts the original WRITE 
routine and invokes it to actually write the tuple.  It then returns a tuple
that contains the timestamp field.  
<p>
Note that there is a check for the Write command being enabled.  
This enabled switch would be set by the START command. For this command
this is really not needed but because the Server internally uses the 
WRITE command, it may be important that the user added WRITE command 
is completely setup before it is turned loose to handle all WRITE 
requests.
<pre>
  if (_enabled)
    ((StaleTuple)argTuple).updateExpirationDate();  
  final TSHandler simpleWrite = ts.mostBasicHandler( TupleSpace.WRITE, argTuple);
  simpleWrite.command( ts, TupleSpace.WRITE, argTuple, clientID_, communicator_, user_);
  retValue.add(argTuple.getField(0));
  return retValue;

</pre>
<p>
The implementation of the START command is quite different.
It gets the parameter that says how often we want to check 
for expired tuples and then calls a special constructor for 
the StaleTupleSpaceHandler to construct a new Runnable instance 
and then it sets up a thread for 
the daemon and starts the thread executing.
<pre>
 
  Field first = argTuple.getField(0);
  final long howOften = ((Long)first.getValue()).longValue();
  StaleTupleSpaceHandler newExecuter = new StaleTupleSpaceHandler(ts,howOften,clientID_, communicator_);
  Thread doTheLoop = new Thread(newExecuter,"StaleKiller");
  doTheLoop.setDaemon( true); // this is a daemon so set it on
  doTheLoop.start();
  _enabled = true;   // enable the WRITE command
</pre>

<p>
The code for the run method is shown below.  Basically it builds a template that 
contains the current date and time and then uses this template to issue a delete 
command that will delete all StaleTuple instances that have an earlier timestamp.
In order to satisfy the transaction locking of TSpaces, it first generates a Client
TransactionID and calls the TransactionManager to begin a transaction. 
After the delete, it call the TransactionManager to commit the transaction.
<pre>
  public void run(){

      long throwOutBeforeThis = System.currentTimeMillis();
      StaleTimestamp timestamp = new StaleTimestamp(throwOutBeforeThis);
      StaleTuple template = new StaleTuple(timestamp);

      int ct =0;
      String myClientID;      
      TransactionManager transMgr = TSServer.getTransMgr();
      
    
      TSHandler simpleDelete = _ts.mostBasicHandler( TupleSpace.DELETE, template);          
      
      while(true) {
        // generate a new Transaction Identifier and tell TransactionManager
        ct++;
        myClientID = _clientID+"START"+ct;        
        int transID = transMgr.beginTrans(myClientID);

        throwOutBeforeThis = System.currentTimeMillis();
        // Create a subclass of Field that contains the current date/time
        timestamp = new StaleTimestamp(throwOutBeforeThis);
        template = new StaleTuple(timestamp);
      
        SuperTuple delTuple = simpleDelete.command( _ts, 
                                     TupleSpace.DELETE, 
                                     template, 
                                     myClientID, 
                                     _communicator, 
                                     _user);
      
        
        transID = transMgr.commitTrans(myClientID);
        
        delay( (int)_howOften) ;
      } 

</pre>
<p>
The sharp eyed reader may have noticed that something is wrong with the above 
description.  The <b>DELETE</b> command only deletes Tuples that match the 
template so it should only delete Tuples that have the exact same timestamp
instead of earlier timestamp.   The reason that this works is that the 
time stamp field is an instance of 
<a href="../examples/handler/StaleTimestamp.java" target=new><b>StaleTimestamp</b></a> 
which implements the 
<b>matches()</b> such that any timestamp that is less than the template timestamp 
will return true. 
</ul>


<hr>
<!------------------------------------>
<h2><a name="xml">XML Support</h2>
<!------------------------------------>


<ul>
<li>
Motivation: why is it here and why would you want to use it.</li>
</ul>
XML is a flexible metadata language that can be useful in a variety of
contexts.&nbsp; Because of its extensible nature, XML can be used to describe
everything from networked devices, corporate command hierarchies, and chemical
reactions, to grocery shopping lists and daily calendars.&nbsp; As a text-based
language, XML is simple, powerful, and easy to understand.&nbsp; As more
and more XML applications integrate themselves into business and daily
applications, the need to store and query XML documents becomes increasingly
evident.&nbsp; While there are very few modular XML storage and query engines
in existence, TSpaces is working to provide that functionality in a scalable
and fault tolerant fashion.
<ul>
<li>
How do you use it?</li>
</ul>
The XML write and query operations are very similar to the corresponding
operations on tuples.&nbsp; To write an XML document, create an XMLField
using the String form of the XML document to be written, and then write
the XMLField to the TSpace inside a tuple.&nbsp; For example, the following
code writes a trivial XML document into the default TSpace:
<pre>
&nbsp;&nbsp; TupleSpace ts = new TupleSpace("xmlTest", server);
&nbsp;&nbsp; String xml = "&lt;?xml version="1.0"?>&lt;MESSAGE>Hello World!&lt;/MESSAGE>";
&nbsp;&nbsp; Field xmlF = new XMLField(xml);
&nbsp;&nbsp; Tuple xmlT = new Tuple("myXML Tuple",xmlF);
&nbsp;&nbsp; ts.write(xmlT);
&nbsp;&nbsp; ...
</pre>
Currently, the XMLField constructor requires that you pass in the entire
content of the XML document as a single String.&nbsp; This limitation will
be fixed in the full release.
<p>
We should mention briefly the internals of the XML support.  When a new
tuple is written to a TSpace containing a XMLField, the XML string content
is passed off and converted into a TupleTree.  A TupleTree is essentially a
tree of tuples, which as a whole mirrors the DOM (Document Object Model)
tree of the XML document.  Tuples are analogous to a node in the XML DOM 
tree.  Each tuple is an instance of XMLTuple and contains a XTuple object.  
The XTuple object is an
encapsulation of the XML specific data for a given node, and contains
TupleID references to the DOM node's parents and siblings.  For information
on the exact contents of the XTuple object, see the JavaDoc.

<p>To make a query on existing XML documents which have been written to
the Space, we use the same query structure that supported AND, OR, and
Index queries.&nbsp; For example, this code excerpt executes a simple query
on the set of XML documents, assuming the previous code block has been
executed:
<pre>
&nbsp;&nbsp; ...
&nbsp;&nbsp; String xql = "/MESSAGE";
&nbsp;&nbsp; Tuple result = ts.scan(new XMLQuery(xql));
&nbsp;&nbsp; System.out.println("Result tuples: "+result);
&nbsp;&nbsp; ...
</pre>
The Tuples which are returned are the Tuples that contain an XMLField that describes
an XML document that has one or more nodes that match the XQL query.
<p>
We need to explain here the exact XML query syntax supported by TSpaces.&nbsp;
In this version of XML query support, we've decided to support a 
subset of the XQL language specification.
XQL is a path expression
based query language proposed to the W3C query workshop.
For detailed
information on XQL, check out the XQL <a href="http://metalab.unc.edu/xql">FAQ</a>.&nbsp;
While reading the FAQ, please keep in mind that TSpaces only supports the
core subset of XQL functionality, namely, those of Tagnames, Tagvalues,
Descendants, and Attribute constraints. 
<p>Put another way, some of the more notable XQL functionality 
that is missing from TSpaces include: 
<ul>
<li>boolean operators connecting multiple conditions (grouping) 
<li>sequences and ordering operators(; and ;;)
<li>semi-joins
<li>return operators(? and ??)
<li>wildcard attributes.
</ul>
<p>To make the TSpace XML queries more real, here are a couple of sample
queries and what they do:
<br>&nbsp;
<center><table BORDER WIDTH="100%" BGCOLOR="#CCFFFF" NOSAVE >
<tr>
<td>/ADDRESS</td>

<td>Return all occurrences of the ADDRESS tag where it is anchored to the
root of the document.</td>
</tr>

<tr>
<td>ADDRESS//ZIP</td>

<td>Return all occurrences of the ZIP tag where it is an eventual descendant
of the ADDRESS tag, which occurs in the same document, but is not required
to be anchored to the root.</td>
</tr>

<tr>
<td>ADDRESS/STREET='CHANNING WAY'</td>

<td>Return all occurrences of the STREET tag where its content is equal
to the 'CHANNING WAY' string, and it is a direct child of the ADDRESS tag.</td>
</tr>

<tr>
<td>/*/ADDRESS[@TYPE='temporary']/CITY</td>

<td>Return all occurrences of the CITY tag where its parent node is ADDRESS,
with an attribute of TYPE with value 'temporary'. The ADDRESS tag
must have a parent which is anchored to the root of the document.</td>
</tr>
</table></center>
<p>
In order to use the new XML support, the server needs to have access to a 
XML parser.  We have used the XML Parser that is available on the IBM Alphaworks
site.  To download the xml4j.jar file that you will require, go to the 
<a href="http://www.alphaWorks.ibm.com/formula/xml" target=new>
http://www.alphaWorks.ibm.com/formula/xml</a> site and request the 
<b>download</b> option.  Specify the <b>xml4j_2_0_15</b> release and download 
the zip file. Then extract the xml4j.jar file and save it somewhere convenient.
To make it accessible to the server, this jar file needs to be in the classpath used 
when you start the server.  If you are using the distributed <b>tspaces.bat</b> file
to start the server, you can simply specify the JAR_XML environment variable.
<pre>
   set JAR_XML=c:\xml\xml4j.jar
   bin\tspaces 
</pre>
<p>
<h4>Temporary Restrictions</h4>
<ul>
<li>A Tuple can only have one XMLField.  

<li>XQL Return operators(?,??) are not supported.<br>
The entire XML document is returned if one or more nodes match the XQL query.
However the XMLField has a <b>getQueryResult()</b> method that will 
return a set of TupleID objects 
that refer to the matching nodes in the document TupleTree.  Refer to the JavaDoc for more information.
An example of creating an XQL-Result document from the information in the 
returned XMLField is in the <b>.../examples/xml/TestXTuple.java</b> example. 
</ul>
<p>
<hr>
<!------------------------------------>
<h2><a name="compile">Compiling TSpaces Applications</h2>
<!------------------------------------>
If you followed the <a href="Install.html" target=new">installation procedures</a> then 
you have a directory on your system that might look like this:
<PRE>
<strong>yourname/</strong>
&nbsp;&nbsp;<strong>tspaces/</strong>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lib/
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tspaces.jar
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tspaces_client.jar
</PRE> 
Let's assume that this is a Unix system and you installed it in the <strong>/u/joe</strong> 
directory.  The important file that you need to worry about is then 
<strong>/u/joe/tspaces/lib/tspaces_client.jar</strong> which contains the TSpaces client class files. 
<p>
If you are using the Sun JDK without any IDE, you need to add the above jar file to the Java CLASSPATH
environment variable or specify it for both the "javac" and "java" command line.
For example:
<pre>
    export CLASSPATH=.:/u/joe/tspaces/lib/tspaces_client.jar
    javac yourfile.java
    java  yourfile

or
   
    javac -classpath .:/u/joe/tspaces/lib/tspaces_client.jar yourfile.java
    java -cp .:/u/joe/tspaces/lib/tspaces_client.jar yourfile
</pre>

If you are using any of the hundreds of IDEs like IBM Visual Age, Symantec Cafe, Kawa etc, 
then you would follow their instructions for integrating jar files into the environment.
However, just because this is distributed in a jar file does not imply that this is 
setup as a JavaBean, it's not. 
<p>
<b>Note:</b> There are certain client services such as the AddHandler facility that 
require access to TSpaces server classes.  For those cases, you should add 
<b>tspaces.jar</b> to the CLASSPATH.  

<hr>

<!------------------------------------>
<h2><a name="server">Running a TSpaces Server</h4>
<!------------------------------------>
In order to actually run your TSpaces client, you need to have an available TSpaces server.  
During the testing phase, you will probably run your own copy of the server on your local machine and 
refer to it with the server name of "localhost".  The sample programs come with a shell script for 
starting a TSpaces server and you may be able to use that script to start your server.
You can refer to the instruction for running the 
sample programs that come with TSpaces for instructions and shell scripts for 
<a href="examples.html#server" target=new>starting a local server.</a>
<p>
If you write your own script or invoke it directly, you have to ensure that 
the CLASSPATH is set correctly so that the jar files that contain the Server code is available.
Let's assume that this is a WinNT system and you installed TSpaces in the <strong>c:\java</strong> 
directory.  The following should be sufficient to run the TSpaces server.  

<pre>
set CLASSPATH=c:\java\tspaces\classes;c:\java\tspaces\lib\tspaces.jar
    
java  com.ibm.tspaces.server.TSServer [options]

</pre>
<p> 
<p>
There are a number of options that can be specified when starting the server.
<pre>
  Options:
  [-a password]        Password for sysadmin userid
  [-b]                        Boot without restoring TupleSpaces
  [-B]          Boot without restoring TupleSpaces or User/Group status
  [-c ConfigurationFile]      specify location of the Configuration file
  [-d checkpointDirectory]    specify a checkpoint directory
  [-p port#]                  specify a port number [default 8200]
  [-i interval]               specify a checkpoint interval
      [-D]                        Turn on Debug output
      [-A]                        Allow Admin actions via http
      [-S]                        Start the HTTP debug interface

  Note that the spaces after the option flags are needed

</pre>
All of the options can be specified by the Configuration file.  If the 
<b>-c</b> option is not specified, it will look for a "tspaces.cfg" in the 
current directory and if still not found, then it will run with a set of hard-coded defaults.
<p>
A sample <b>tspaces.cfg</b> file is distributed with the system that contains 
comments about the options.       
<h4>Special Considerations</h4>
An important factor to keep in mind is the requirement that the Server have access to the class
definitions for any objects that are written to or read from the server.  The fact that the server 
has access to the class definitions for the objects that are contained in the tuples, gives TSpaces 
the ability to do selection on any fields of the tuple.  But this also can be a problem area.
<p>
So you should ensure that the CLASSPATH that is used when starting the server, includes the directory 
where the client class files are placed 
(usually the current directory at compile time or specified via "java -d classdir").
<p> 
Also, once the class file is loaded by the server, that version continues to be used.
So if you correct a bug in the client class and recompile, you may need to restart the server.  
Of course, use of the Serialver option will make this unnecessary. See the 
<a href="#userobjects">User Objects Example</a> for an example of this.  
<p> 
Another consideration with the above, is that when you allow user objects to be sent 
to the server, then certain methods of those objects will be invoked in the server Virtual 
Machine.  This may be a security problem and/or a reliability problem.  
In general, if you have a TSpaces server with sensitive data in it and/or 
reliability is important, you probably want to 
have tight control over the placement of client Java class files into the Server library.
The earlier section on 
<a href="#userobjects">User Objects</a> describes how one can bypass these 
problems with Object PreSerialization.

<hr>
<!------------------------------------>
<h2><a name="ServerAccessControl">Access Control Server Setup</h2>
<!------------------------------------>
The TSpaces server supports authentication of the Clients and Access Control List(ACL)
protection of each Space.  
<p>
<ul>
<li><h4>Authentication support</h4>
The TSpaces clients identify themselves by specifying a userid and password on the 
TupleSpace constructor call.  For an example of this, see 
<a href="#ClientAccessControl">Access Support example</a> 
<p>
The server maintains a Hashtable of Userids and password keys.  These 
password keys are the passwords from the user that have been turned into a digest by the 
SHA algorithm that is part of java.security and then the results turned into a BigInteger.

The user/password combinations can either be read from the config file (not recommended) or
entered via the <b>Admin</b> application.   
The Hashtable is currently written in a tuple to the Admin space and also to a file for backup
in case the server does not have checkpointing or is rebooted.  
<p>

The client code in TupleSpace takes the password supplied on the constructor and 
turns it into a BigInteger and then sends the BigInteger over the socket 
where it is compared to the BigInteger maintained by the server.   
So since the SHA digest is non-reversable,  
anyone seeing the socket data or looking at the file on disk, 
would not be able to determine the original password.  
<p>
The above enables the client to securely tell the Server who they are.  If
not specified by the client, then the userid of "anonymous" is used.  


<p>
Although currently the Userid and group structure is managed by TSpaces,
the design is such that in the future, the User/Group configuration could be 
interfaced to the installation's User/Group setup for the Operating System 
where the T Space server is running. 

<p>
<li><h4>Access Control List support</h4>

The java.security interfaces are 
<ul>
<li>Principal:  represents a user or group.  It has a name and not much else.
<li>Group:  a subclass of Principal.  It has members that are other principals
<li>AclEntry: represents the Permissions for a Principal. Can be negative or positive. 
<li>Acl: represents the Access Control list for some resource (i.e. a TupleSpace)
It has a name and contains a set of ACLEntry objects. 
It has methods for checking that a given Principal has the specified
Permissions. 
<li>Permission:  Represents a Permission - contains an equals() method to test it.
There are both general Permissions of Read, Write, Owner, and Admin.  All current TSpaces 
commands can be given permissions in combinations of these permissions.  In addition, one 
can have specific permissions that only apply to a single command.  So, for example, 
one could implement a command named "SpecialCmd" and only invoke it 
if the caller has "SpecialCmd" permission for that Space.
</ul>
</ul>  
<p>
 
The initial hierarchy group and user hierarchy is built from the Server Configuration file.
the first time that the server is started or when the "-B" operand is specified on startup.
If you look at the <b>tspaces.cfg</b> file that is distributed with TSpaces, you will see
that it sets up a very basic hierarchy with the top level group <b>users</b> that contains
a subgroup of <b>AdminGroup</b> and the users <b>sysadmin</b>, <b>guest</b> and <b>anonymous</b>.  

The comments in the file will hopefully show how one could enhance this.
Based on the configuration file, a TsACLDBase object is built that contains a linked list 
that represents the User/Group hierarchy and this object is written to the Admin Space on the 
server.
<p>
Also a DefaultACL is built based on the configuration file.  The default ACL is the ACL  
used for any Space that is created without specifying an ACL.  
If there is no config file, then we build an ACL that gives Read,write authority to 
group Users and read,write,admin authority to sysadmin. 
The CreateAcl is also built based on the configuration file. 
It is used to control who has permission to create a new space.  The default is to 
grant all users, including anonymous, the permission to create Spaces.  
<p>
The default ACLs and  any ACLs that are created when a new Space is created are 
written and maintained in the Admin Space.  
<p>
<!------------------------------------>
<h2><a name="AdminApp">Using the Admin Application</h2>
<!------------------------------------>
There is a very basic <b>Admin</b> application distributed with the system that allows the 
"Administration user" to manipulate both the User/Group hierarchy and the ACL entries that 
protect the individual Spaces.  To invoke the application, issue the following commands:
<pre>
  cd  your_tspaces_directory
  bin\admin.bat   [host] [port] [userid] [password]              
</pre>
This application uses the Java JFC "Swing" classes 
<a href="http://java.sun.com/products/jfc" target=new>("Swing 1.1")</a>.  These are included with 
Java 1.2 but if you have Java 1.1 then you must install the Swing classes yourself  
and the <b>SWING_HOME</b> environment variable must be specified.  We apologize in advance for
slow load time of the application,  it takes awhile to load the Swing classes.
Also this is work in process, so it is not as easy to use this application as we would have liked.  
One hint is that it does use popup menus, so click the mouse button assigned to "popup" 
on a user or group entry. That will bring up the menu options to add or delete users or groups.
Clicking it on an Acl permission entry will allow you to modify or add new AclEntry objects.
<p>
The user/group hierarchy information and the user/password information is stored in the 
TSpaces Admin space.  But because you may want to run the server in non Persistent mode, 
it is also backed up into files so you will not lose your user/group information when you 
restart.
These backup files (acldb.ser and password.ser) are stored in the current directory. 
If you want to completely start from scratch and get the initial ACL information from the 
configuration file then you should specify the <b>-B</b> flag on the command line. 
<p>

<hr>
<!------------------------------------>
<h2><a name="localserver">Starting a Local Server </h2>
<!------------------------------------>
Sometimes it is useful to have the client actually run the server 
as a thread inside that same Java Virtual Machine as the client. 
It lets the client control the starting and stopping of the clients
and may give significant performance enhancements.
For example, it might be useful when you have many clients on remote systems 
providing input to a main central server where they are processed
by a local client. In this case you want the local client to be able to 
access TSpaces as fast as possible.  
<p>

A new interface between the client and the Server is available 
for the case where the client and the server are running on the
same machine and under the same Java Virtual Machine. 
In this case, the client calls are directly implemented by the 
Server without the TCPIP socket overhead.  Under certain circumstances,
it can also reduce the overhead of Object serialization.
<p> 
To do this the client must start the server with the following 
code:
<p>
<pre>
  TSServer ts = new TSServer();
  Thread serverThread = new Thread( ts, "TSServer" );
  serverThread.start();
</pre>
The above TSServer default constructor will let all of the command 
line options have the
default values, including having the default tspaces.cfg file 
in the current directory.
You can refer to the JavaDoc API for TSServer to see how you would 
specify other options for the server. 
<p>
Now to use the new high performance interface that avoids
all TCPIP socket overhead, you add
the following line to your client code:
<pre>
  TupleSpace.setTSCmdImpl("com.ibm.tspaces.TSCmdLocalImpl");
</pre>
<p>
The rest of your code is unchanged.  It should be noted that this 
special interface will be used only by this client.  Any other clients 
on another system or even on this system but under a different JVM will
continue to use the socket interface to communicate with this server. 
<p>
The local interface can avoid much of the overhead of Object 
Serialization under some circumstances.  
It important that the objects stored in the server be 
independent from the objects that the client is manipulating.
If the client and the server are both running under the same JVM, 
then this means that when an object is transfered from the client
to the server (or viceversa) that the server gets a copy of the object.
If the Tuple consists of only String and Number fields, then this copy 
is done by a call to the Tuple.clone method which is relatively efficient.
Otherwise, the copy is made by calling the same Object Serialization
routines that are used when the client and server talk over a socket
interface. 
<p>
The bottom line is: if you have an application where the Tuples consist
of only String and Number fields and you have a client that needs high 
performance and can run on the same system as the TSpaces server, then
using this special local interface may be worthwhile.



<hr>
<!------------------------------------>
<h2><a name="httpserver">HTTP Server Interface</h2>
<!------------------------------------>
The TSpaces Server contains a built-in HTTP Server
that can be accessed via a Web Browser interface 
This interface can be used to determine the status of TSpaces, 
obtain debug information, or even download HTML and Java Applets.
 <ul>
   <li>To access the HTTP server to obtain status or debug 
  information you would use the following URL:
  <pre>
   http://hostname:8201/debug
  </pre>
  <li>To access applets or HTML files, place the files into a 
  directory on the server and set the following Configuration entries.
  <pre>
  [HTTPServer]
  HTTPServerSupport =  true      
  HttpPort    =    8201
  # Specify the directory where downloadable class files are kept
  ClassesDirectory  =   c:\tspaces\
  </pre>
 </ul>

<! ---------------------------------------------------------------------> <hr>
<p>
<!----------------------------------------------------------------->
<hr>
<! ------------------------------------------------------------------------->
[
<a href="../index.html" target=_top>
TSpaces home page </a>
]

</body>
